#include <stdio.h>
#include "raylib.h"

// 游戏状态
typedef enum GAME_STATE {
    GAME_STATE_PLAYING, GAME_STATE_FAIL, GAME_STATE_WIN,
} GAME_STATE;

// 移动方向
typedef enum MOVE_DIRECTION {
    MOVE_DIRECTION_UP_LEFT, MOVE_DIRECTION_UP_RIGHT,
    MOVE_DIRECTION_RIGHT, MOVE_DIRECTION_RIGHT_DOWN,
    MOVE_DIRECTION_LEFT_DOWN, MOVE_DIRECTION_LEFT
} MOVE_DIRECTION;

// 行列
typedef struct PosRowCol { int row; int col; } PosRowCol;

const int MAX_STEPS = 10;   // 最大步数
const int ROWS = 8;         // 行数
const int COLS = 8;         // 列数
const int CELL_WIDTH = 64;  // 宽度
const int CELL_HEIGHT = 64; // 高度
const int CELL_SPACE = 4;   // 间距 
const int ROLE_FRAME_TOTAL = 7;         // 总帧数
const float FRAME_INTERVAL = 1 / 6.f;   // 帧间隔
const PosRowCol ROLE_START_POS = {4, 4};// 角色初始位置
#define MOVE_DIRECTION_TOTAL 6  // 移动方向总数
// 朝每个方向移动的距离
const int DIRECTION_DELTA[2][MOVE_DIRECTION_TOTAL][2] = {
    // 偶数行
    { {-1, -1}, {-1, 0}, {0, 1}, {1, 0}, {1, -1}, {0, -1}, },
    // 奇数行
    { {-1, 0}, {-1, 1}, {0, 1}, {1, 1}, {1, 0}, {0, -1}, },
};

Texture textPot;
Texture textXxy;
Texture textRestart;
Texture textGege[ROLE_FRAME_TOTAL];

Sound sndFail;  // 失败音效 我们失败了 cxk成功了 “厉不厉害你坤哥”
Sound sndWin;   // 成功音效 我们成功了 cxk失败了 “你干嘛”
Sound sndNv[3]; // 女生的声音

GAME_STATE gameState = GAME_STATE_PLAYING;

// 地图
int layerGrid[ROWS][COLS];
// cxk位置
PosRowCol rolePos;
int layerFans[ROWS][COLS];

// cxk动画相关参数
int frameIdx = 0;
float frameTime = 0.0;

void init();
void initGame();
void loadTextures();
void loadSounds();
void drawGrid();
void drawRole(float dt);
void drawWin();
void drawFail();

void checkMouseClick();
Vector2 getPosOfRowCol(int row, int col);
PosRowCol getRowColOfPos(Vector2 pos);
bool showButton(Texture text, Vector2 pos);
void escape();
int escapeLength(int row, int col, MOVE_DIRECTION direction);
void checkFail();
void checkWin();

int main() {
    init();
    while (!WindowShouldClose()) {
        checkMouseClick();
        BeginDrawing();
            drawGrid();
            drawRole(GetFrameTime());
            drawWin();
            drawFail();
        EndDrawing();
    }
    CloseWindow();
    return 0;
}

void init() {
    InitWindow(650, 650, "Catch Cat");
    SetTargetFPS(60);
    loadTextures();
    loadSounds();
    initGame();
}

void initGame() {
    gameState = GAME_STATE_PLAYING;
    rolePos.row = ROLE_START_POS.row;
    rolePos.col = ROLE_START_POS.col;

    for (int row = 0; row < ROWS; row++) {
        for (int col = 0; col < COLS; col++) {
            // 1/4概率放粉丝
            if (GetRandomValue(0, 3) == 0 
                && rolePos.row != row && rolePos.col != col) {
                layerGrid[row][col] = 1;
            } else {
                layerGrid[row][col] = 0;
            }
        }
    }
}

void loadTextures() {
    textPot = LoadTexture("res/pot.png");
    textXxy = LoadTexture("res/xxy.png");
    textRestart = LoadTexture("res/restart.png");
    for (int i = 0; i < ROLE_FRAME_TOTAL; i++) {
        char str[20];
        sprintf(str, "res/gg%d.png", i);
        textGege[i] = LoadTexture(str);
    }
}

void loadSounds() {
    InitAudioDevice();

    sndWin = LoadSound("res/sef_fail.mp3");
    sndFail = LoadSound("res/sef_win.mp3");
    for (int i = 0; i != 3; i++) {
        char buf[20];
        sprintf(buf, "res/nv%d.wav", i);
        sndNv[i] = LoadSound(buf);
    }
}

void checkMouseClick() {
    if (gameState != GAME_STATE_PLAYING) return;

    if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) {
        PosRowCol rcPos = getRowColOfPos(GetMousePosition());
        if (rcPos.row == -1) return;

        int row = rcPos.row;
        int col = rcPos.col;
        if (layerGrid[row][col] == 0) {
            layerGrid[row][col] = 1;
            PlaySound(sndNv[GetRandomValue(0, 2)]);
        }
        escape();
    }
}

void drawGrid() {
    ClearBackground((Color){231, 231, 231, 255});
    for (int row = 0; row < ROWS; row++) {
        for (int col = 0; col < COLS; col++) {
            Vector2 pos = getPosOfRowCol(row, col);
            if (layerGrid[row][col] == 0) {
                DrawTextureRec(textPot, (Rectangle){0, 0, 64, 64}, pos, WHITE);
            } else {
                DrawTexture(textXxy, pos.x, pos.y, WHITE);
            }
        }
    }
}

Vector2 getPosOfRowCol(int row, int col) {
    Vector2 startPos = (Vector2){46, 51};
    int x = startPos.x + col * (CELL_WIDTH + CELL_SPACE);
    int y = startPos.y + row * (CELL_HEIGHT + CELL_SPACE);
    if (row % 2 == 1) x += CELL_WIDTH / 2;

    return (Vector2){x, y};
}

PosRowCol getRowColOfPos(Vector2 pos) {
    PosRowCol rcPos = {-1, -1};
    for (int row = 0; row < ROWS; row++) {
        for (int col = 0; col < COLS; col++) {
            Vector2 posOfCell = getPosOfRowCol(row, col);
            if (pos.x >= posOfCell.x && pos.x <= posOfCell.x + CELL_WIDTH 
            && pos.y >= posOfCell.y && pos.y <= posOfCell.y + CELL_HEIGHT) {
                rcPos.row = row;
                rcPos.col = col;
                break;
            }
        }
    }
    return rcPos;
}

void drawRole(float dt) {
    frameTime += dt;
    if (frameTime >= FRAME_INTERVAL) {
        frameTime -= FRAME_INTERVAL;
        frameIdx = (frameIdx + 1) % ROLE_FRAME_TOTAL;
    }
    Vector2 pos = getPosOfRowCol(rolePos.row, rolePos.col);

    pos.y -= 30;
    pos.x += 5;
    DrawTexturePro(textGege[frameIdx], 
    (Rectangle){0, 0, textGege[frameIdx].width, textGege[frameIdx].height}, 
    (Rectangle){pos.x, pos.y, 55, 80}, (Vector2){0, 0}, 0, WHITE);
}

void drawWin() {
    if (gameState != GAME_STATE_WIN) return;

    DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), (Color){0, 0, 0, 128});
    DrawText("YOU WIN", 220, 250, 50, WHITE);

    if (showButton(textRestart, (Vector2){280, 350})) initGame();
}

void drawFail() {
    if (gameState != GAME_STATE_FAIL) return;

    DrawRectangle(0, 0, GetScreenWidth(), GetScreenHeight(), (Color){0, 0, 0, 128});
    DrawText("YOU FAIL", 220, 250, 50, WHITE);

    if (showButton(textRestart, (Vector2){280, 350})) initGame();
}

bool showButton(Texture text, Vector2 pos) {
    Color color = WHITE;
    Rectangle rec = (Rectangle){pos.x, pos.y, text.width, text.height};
    Vector2 mousePoint = GetMousePosition();
    bool clicked = false;
    if (CheckCollisionPointRec(mousePoint, rec)) {
        if (IsMouseButtonDown(MOUSE_LEFT_BUTTON)) {
            color = (Color){127, 127, 127, 255};
        } else if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) {
            clicked = true;
        } else {
            color = (Color){200, 200, 200, 255};
        }
    }
    DrawTexture(text, pos.x, pos.y, color);
    return clicked;
}

void escape() {
    // 查找6个方向的通路 选择一个最短路径
    // 存储6个方向的步数
    int steps[MOVE_DIRECTION_TOTAL] = {0};
    for (int dirct = 0; dirct < MOVE_DIRECTION_TOTAL; dirct++) {
        steps[dirct] = escapeLength(rolePos.row + DIRECTION_DELTA[rolePos.row % 2][dirct][0], 
            rolePos.col + DIRECTION_DELTA[rolePos.row % 2][dirct][1], dirct);
    }
    int minStep = MAX_STEPS;
    int minDirect = -1;
    for (int dirct = 0; dirct < MOVE_DIRECTION_TOTAL; dirct++) {
        if (steps[dirct] < minStep) {
            minStep = steps[dirct];
            minDirect = dirct;
        }
    }

    if (minStep < MAX_STEPS) {
        rolePos = (PosRowCol){rolePos.row + DIRECTION_DELTA[rolePos.row % 2][minDirect][0], 
            rolePos.col + DIRECTION_DELTA[rolePos.row % 2][minDirect][1]};
        checkFail();
        checkWin();
        return;
    }

    // 6个方向都没有通路，随机选择1个方向
    PosRowCol srounds[MOVE_DIRECTION_TOTAL];
    int sroundsCount = 0;
    for (int dirct = 0; dirct < MOVE_DIRECTION_TOTAL; dirct++) {
        PosRowCol prc = (PosRowCol){rolePos.row + DIRECTION_DELTA[rolePos.row % 2][dirct][0], 
            rolePos.col + DIRECTION_DELTA[rolePos.row % 2][dirct][1]};
        if (layerGrid[prc.row][prc.col] == 0) {
            srounds[sroundsCount++] = prc;
        }
    }

    if (sroundsCount > 0) {
        int index = GetRandomValue(0, sroundsCount - 1);
        rolePos = srounds[index];
    }

    checkFail();
    checkWin();
}

// 获取方向的逃跑
int escapeLength(int row, int col, MOVE_DIRECTION direction) {
    // 已经到达边界了返回1
    if (row < 0 || row >= ROWS || col < 0 || col >= COLS) return 1;

    // 当前是节点是障碍物，返回MAX
    if (layerGrid[row][col] != 0) return MAX_STEPS;

    return escapeLength(row + DIRECTION_DELTA[row % 2][direction][0], 
                col + DIRECTION_DELTA[row % 2][direction][1], direction) + 1;
}

void checkFail() {
    if (gameState != GAME_STATE_PLAYING) return;

    // 检测失败 哥哥走到边缘
    if (rolePos.row == 0 || rolePos.row == ROWS - 1 
        || rolePos.col == 0 || rolePos.col == COLS - 1) {
        PlaySound(sndFail);
        gameState = GAME_STATE_FAIL;
    }
}

void checkWin() {
    if (gameState != GAME_STATE_PLAYING) return;
    // 哥哥周围6个方向都没有通路了 则我们成功
    bool win = true;
    for (int dirct = 0; dirct < MOVE_DIRECTION_TOTAL; dirct++) {
        PosRowCol prc = (PosRowCol){rolePos.row + DIRECTION_DELTA[rolePos.row % 2][dirct][0], 
            rolePos.col + DIRECTION_DELTA[rolePos.row % 2][dirct][1]};
        if (layerGrid[prc.row][prc.col] == 0) {
            win = false;
            break;
        }
    }
    if (win) {
        PlaySound(sndWin);
        gameState = GAME_STATE_WIN;
    }
}
